//==================================================================
//  Copyright (C) 2006-2007  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
//= Creation: Davide Pasca 2005
//=
//= Based on Mark R. Nelson source from Dr.Dobb's
//=
//==================================================================

#ifndef PUTILS_LZW_PACKER_H
#define PUTILS_LZW_PACKER_H

//==================================================================
#include "psys.h"
#include "memfile.h"

//==================================================================
//namespace PUtils {

bool LZW_PackCompress( PUtils::Memfile *input, PUtils::Memfile *output );
bool LZW_UnpackExpand( PUtils::Memfile *input, PUtils::Memfile *output );

//==================================================================
//};

//==================================================================
#define LZW_BITS			12				// Setting the number of bits to 12, 13
#define LZW_HASHING_SHIFT	(LZW_BITS-8)	//  or 14 affects several constants.
#define LZW_MAX_VALUE		((1 << LZW_BITS) - 1)	// Note that MS-DOS machines need to   */
#define LZW_MAX_CODE		(LZW_MAX_VALUE - 1)		// compile their code in large model if*/

#if LZW_BITS == 14
	#define LZW_TABLE_SIZE 18041				// The string table size needs to be a
#elif LZW_BITS == 13							// prime number that is somewhat larger
	#define LZW_TABLE_SIZE 9029					// than 2**BITS.
#elif LZW_BITS <= 12
	#define LZW_TABLE_SIZE 5021
#endif

//==================================================================
class LZWUnpacker
{
	PUtils::Memfile *_input;
	
	u_int	_prefix_code[LZW_TABLE_SIZE];		// This array holds the prefix codes
	u_char	_append_character[LZW_TABLE_SIZE];	// This array holds the appended chars
	u_char	_decode_stack[4000];				// This array holds the decoded string

	bool			_completed;
	u_int			_next_code;
	u_int			_new_code;
	u_int			_old_code;
	int				_character;
	int				_counter;
	const u_char	*_string;

public:
	LZWUnpacker( PUtils::Memfile *input=NULL );

	void	Reset( PUtils::Memfile *input );
	bool	UnpackData( PUtils::Memfile *output, u_int max_out_bytes );
	bool	IsCompleted() const
	{
		return _completed;
	}
	bool	SeekEnd();

private:
	u_int unpackInputCode( PUtils::Memfile *input );
	const u_char *unpackDecodeString( u_char *buffer, u_int code );
};

//==================================================================
class LZWPacker
{
	PUtils::Memfile *_output;

	int		_pack_code_value[LZW_TABLE_SIZE];	// This is the code value array
	u_int	_prefix_code[LZW_TABLE_SIZE];		// This array holds the prefix codes
	u_char	_append_character[LZW_TABLE_SIZE];	// This array holds the appended chars

	u_int	_next_code;
	u_int	_string_code;
	bool	_is_beginnig;

public:
	LZWPacker( PUtils::Memfile *output=NULL );

	void	Reset( PUtils::Memfile *output );
	bool	PackData( PUtils::Memfile *input );
	bool	EndData();

private:
	void	packOutputCode( u_int code );
	u_int	packFindMatch( int hash_prefix, u_int hash_character );
};

#endif
